如何创建一个 class 实例化仅在满足特定条件时才会发生?
How do I create a class where instantiation only happens if certain conditions are met?
假设我有这个 class:
class Person:
def __init__(self, name):
self.name = name
如果我想实例化Person
我可以这样做:
me = Person("António")
但是,如果 name
的类型为 str
,我只想实例化 Person
怎么办?
我试过这个:
class Person:
def __init__(self, name):
if type(name) == str:
self.name = name
但是当我这样做的时候:
me = Person("António")
print(me.name)
you = Person(1)
print(you.name)
我明白了:
所以发生的一切是:
- 如果
name
是 str
,实例有一个 .name
方法
- 如果
name
不是str
,实例没有.name
方法
但我真正想要的是,如果名称不是 str
,则停止所有实例化。
换句话说,我希望不可能使用非 str
name
.
从 Person
class 创建对象
我该怎么做?
怎么样:
class Person:
def __init__(self, name):
if type(name) == str:
self.name = name
else:
raise Exception("name attribute should be a string")
您可以使用检查参数的工厂,如果一切正常,则 returns 使用 Person
对象,否则会引发错误:
也许是这样的:
class PersonNameError(Exception):
pass
class Person:
def __init__(self):
self.name = None
def person_from_name(name: str) -> Person:
"""Person factory that checks if the parameter name is valid
returns a Person object if it is, or raises an error without
creating an instance of Person if not.
"""
if isinstance(name, str):
p = Person()
p.name = name
return p
raise PersonNameError('a name must be a string')
p = person_from_name('Antonio')
鉴于:
p = person_from_name(123) # <-- parameter name is not a string
抛出异常:
PersonNameError Traceback (most recent call last)
<ipython-input-41-a23e22774881> in <module>
14
15 p = person_from_name('Antonio')
---> 16 p = person_from_name(123)
<ipython-input-41-a23e22774881> in person_from_name(name)
11 p.name = name
12 return p
---> 13 raise PersonNameError('a name must be a string')
14
15 p = person_from_name('Antonio')
PersonNameError: a name must be a string
你应该使用 factory design pattern
。您可以阅读更多相关信息 here。简单来说:
创建 Class/method 将检查条件和 return 新的 class 实例,仅当满足这些条件时。
如果您想修改实例化行为,
你可以创建一个构造函数,
使用 class 方法。
class Person:
def __init__(self, name):
self.name = name
print("ok")
@classmethod
def create(cls, name):
if not isinstance(name, str):
raise ValueError(f"Expected name to be a string, got {type(name)}")
return cls(name)
me = Person.create("António")
print(me.name)
you = Person.create(1)
print(you.name)
OK打印一次证明只实例化一次
ok
António
Traceback (most recent call last):
File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 31, in <module>
start(fakepyfile,mainpyfile) File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 30, in start
exec(open(mainpyfile).read(), __main__.__dict__)
File "<string>", line 17, in <module>
File "<string>", line 11, in create
ValueError: Expected name to be a string, got <class 'int'>
[Program finished]
这里是正在进行的显式测试。
很少需要覆盖 new 并且对于日常正常的 classes 我认为应该避免。这样做可以使 class 实现变得简单。
class Test(object):
print("ok")
def __new__(cls, x):
if isinstance(x, str) :
print(x)
else:
raise ValueError(f"Expected name to be a string, got {type(x)}")
obj1 = Test("António")
obj2 = Test(1)
ok
António
Traceback (most recent call last):
File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 31, in <module>
start(fakepyfile,mainpyfile) File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 30, in start
exec(open(mainpyfile).read(), __main__.__dict__)
File "<string>", line 14, in <module>
File "<string>", line 10, in __new__
ValueError: Expected name to be a string, got <class 'int'>
[Program finished]
假设我有这个 class:
class Person:
def __init__(self, name):
self.name = name
如果我想实例化Person
我可以这样做:
me = Person("António")
但是,如果 name
的类型为 str
,我只想实例化 Person
怎么办?
我试过这个:
class Person:
def __init__(self, name):
if type(name) == str:
self.name = name
但是当我这样做的时候:
me = Person("António")
print(me.name)
you = Person(1)
print(you.name)
我明白了:
所以发生的一切是:
- 如果
name
是str
,实例有一个.name
方法 - 如果
name
不是str
,实例没有.name
方法
但我真正想要的是,如果名称不是 str
,则停止所有实例化。
换句话说,我希望不可能使用非 str
name
.
Person
class 创建对象
我该怎么做?
怎么样:
class Person:
def __init__(self, name):
if type(name) == str:
self.name = name
else:
raise Exception("name attribute should be a string")
您可以使用检查参数的工厂,如果一切正常,则 returns 使用 Person
对象,否则会引发错误:
也许是这样的:
class PersonNameError(Exception):
pass
class Person:
def __init__(self):
self.name = None
def person_from_name(name: str) -> Person:
"""Person factory that checks if the parameter name is valid
returns a Person object if it is, or raises an error without
creating an instance of Person if not.
"""
if isinstance(name, str):
p = Person()
p.name = name
return p
raise PersonNameError('a name must be a string')
p = person_from_name('Antonio')
鉴于:
p = person_from_name(123) # <-- parameter name is not a string
抛出异常:
PersonNameError Traceback (most recent call last)
<ipython-input-41-a23e22774881> in <module>
14
15 p = person_from_name('Antonio')
---> 16 p = person_from_name(123)
<ipython-input-41-a23e22774881> in person_from_name(name)
11 p.name = name
12 return p
---> 13 raise PersonNameError('a name must be a string')
14
15 p = person_from_name('Antonio')
PersonNameError: a name must be a string
你应该使用 factory design pattern
。您可以阅读更多相关信息 here。简单来说:
创建 Class/method 将检查条件和 return 新的 class 实例,仅当满足这些条件时。
如果您想修改实例化行为, 你可以创建一个构造函数, 使用 class 方法。
class Person:
def __init__(self, name):
self.name = name
print("ok")
@classmethod
def create(cls, name):
if not isinstance(name, str):
raise ValueError(f"Expected name to be a string, got {type(name)}")
return cls(name)
me = Person.create("António")
print(me.name)
you = Person.create(1)
print(you.name)
OK打印一次证明只实例化一次
ok
António
Traceback (most recent call last):
File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 31, in <module>
start(fakepyfile,mainpyfile) File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 30, in start
exec(open(mainpyfile).read(), __main__.__dict__)
File "<string>", line 17, in <module>
File "<string>", line 11, in create
ValueError: Expected name to be a string, got <class 'int'>
[Program finished]
这里是正在进行的显式测试。 很少需要覆盖 new 并且对于日常正常的 classes 我认为应该避免。这样做可以使 class 实现变得简单。
class Test(object):
print("ok")
def __new__(cls, x):
if isinstance(x, str) :
print(x)
else:
raise ValueError(f"Expected name to be a string, got {type(x)}")
obj1 = Test("António")
obj2 = Test(1)
ok
António
Traceback (most recent call last):
File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 31, in <module>
start(fakepyfile,mainpyfile) File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 30, in start
exec(open(mainpyfile).read(), __main__.__dict__)
File "<string>", line 14, in <module>
File "<string>", line 10, in __new__
ValueError: Expected name to be a string, got <class 'int'>
[Program finished]