[英]How do I create a class where instantiation only happens if certain conditions are met?
Let's say I have this class:假设我有这门课:
class Person:
def __init__(self, name):
self.name = name
If I want to instantiate Person
I can do:如果我想实例化
Person
我可以这样做:
me = Person("António")
But what if I only want to instantiate Person
if name
has type str
?但是如果我只想实例化
Person
如果name
类型是str
呢?
I tried this:我试过这个:
class Person:
def __init__(self, name):
if type(name) == str:
self.name = name
But then when I do:但是当我这样做时:
me = Person("António")
print(me.name)
you = Person(1)
print(you.name)
I get this:我明白了:
So all that's happening is:所以发生的一切是:
name
is str
, the instance has a .name
methodname
是str
,则实例有一个.name
方法name
is not str
, the instance has no .name
methodname
不是str
,则实例没有.name
方法But what I actually want, is to stop instantiation all together if name is not an str
.但我真正想要的是,如果 name 不是
str
,则一起停止实例化。
In other words, I want it to be impossible to create an object from the Person
class with a non str
name
.换句话说,我希望不可能从
Person
类创建一个非str
name
。
How can I do that?我怎样才能做到这一点?
You could use a factory that checks the parameters, and returns a Person
object if everything is fine, or raises an error:您可以使用工厂来检查参数,如果一切正常或引发错误,则返回一个
Person
对象:
maybe something line this:也许是这样的:
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')
Whereas:然而:
p = person_from_name(123) # <-- parameter name is not a string
throws an exception:抛出异常:
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
How about :怎么样 :
class Person:
def __init__(self, name):
if type(name) == str:
self.name = name
else:
raise Exception("name attribute should be a string")
If you want to modify instantiation behaviour, You can create a constructor, using a class method.如果要修改实例化行为,可以使用类方法创建构造函数。
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 prints once proving only once instantiation 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]
Here, it's an explicit test that's being done.在这里,这是一个正在完成的显式测试。 Overriding new is very rarely needed and for everyday normal classes I think it should be avoided.
很少需要覆盖new并且对于日常正常课程,我认为应该避免它。 Doing so keeps the class implementation simple.
这样做可以使类实现简单。
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]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.