#python #scope
#python #область
Вопрос:
В следующем сценарии:
def update_dict(key):
my_dict[key] = ...
mydict = dict()
k = ...
update_dict(k)
my_dict
не было объявлено в классе, но оно использовалось update_dict
.
1- Интерпретатор позволил этому произойти. Разве python не должен выдавать ошибку при этом?
2. Какие проблемы может вызвать использование глобальной переменной без объявления ее как глобальной в локальной области видимости, в которой она используется? Использует ли python указатель на глобальную переменную на основе имени переменной?
Этот фрагмент представляет собой краткое изложение, сделанное мной, и полный код следует за этим абзацем, если вы считаете (возможно, правильно?) что я допустил ошибку в своем резюме. Эквивалент mydict
здесь sites
.
import sys
import csv
import argparse
import gzip
class SiteStats:
def __init__(self, g_size, g_seq):
self.num_reads = 0
self.called_sites = 0
self.called_sites_methylated = 0
self.group_size = g_size
self.sequence = g_seq
def update_call_stats(key, num_called_cpg_sites, is_methylated, sequence):
if key not in sites:
sites[key] = SiteStats(num_called_cpg_sites, sequence)
sites[key].num_reads = 1
sites[key].called_sites = num_called_cpg_sites
if is_methylated > 0:
sites[key].called_sites_methylated = num_called_cpg_sites
parser = argparse.ArgumentParser( description='Calculate methylation frequency at genomic CpG sites')
parser.add_argument('-c', '--call-threshold', type=float, required=False, default=2.0)
parser.add_argument('-s', '--split-groups', action='store_true')
args, input_files = parser.parse_known_args()
assert(args.call_threshold is not None)
sites = dict()
# iterate over input files and collect per-site stats
for f in input_files:
if f[-3:] == ".gz":
in_fh = gzip.open(f, 'rt')
else:
in_fh = open(f)
csv_reader = csv.DictReader(in_fh, delimiter='t')
for record in csv_reader:
num_sites = int(record['num_motifs'])
llr = float(record['log_lik_ratio'])
# Skip ambiguous call
if abs(llr) < args.call_threshold * num_sites:
continue
sequence = record['sequence']
is_methylated = llr > 0
# if this is a multi-cpg group and split_groups is set, break up these sites
if args.split_groups and num_sites > 1:
c = str(record['chromosome'])
s = int(record['start'])
e = int(record['end'])
# find the position of the first CG dinucleotide
sequence = record['sequence']
cg_pos = sequence.find("CG")
first_cg_pos = cg_pos
while cg_pos != -1:
key = (c, s cg_pos - first_cg_pos, s cg_pos - first_cg_pos)
update_call_stats(key, 1, is_methylated, "split-group")
cg_pos = sequence.find("CG", cg_pos 1)
else:
key = (str(record['chromosome']), int(record['start']), int(record['end']))
update_call_stats(key, num_sites, is_methylated, sequence)
# header
print("t".join(["chromosome", "start", "end", "num_motifs_in_group", "called_sites", "called_sites_methylated", "methylated_frequency", "group_sequence"])
)
sorted_keys = sorted(list(sites.keys()), key = lambda x: x)
for key in sorted_keys:
if sites[key].called_sites > 0:
(c, s, e) = key
f = float(sites[key].called_sites_methylated) / sites[key].called_sites
print("%st%st%st%dt%dt%dt%.3ft%s" % (c, s, e, sites[key].group_size, sites[key].called_sites, sites[key].called_sites_methylated, f, sites[k
ey].sequence))
Спасибо!
Комментарии:
1. «1- Интерпретатор позволил этому произойти. Разве python не должен выдавать ошибку при этом? » Нет, с чего бы это? Когда возникнет ошибка и почему?
2. «2- Какие проблемы могут возникнуть при использовании глобальной переменной без объявления ее как глобальной в локальной области, в которой она используется?» Вообще ничего. Никогда не нужно использовать
global
, когда вы просто хотите использовать глобальную переменную. Скорее, это необходимо только при попытке присвоить глобальной переменной внутри функции. Действительно, использованиеglobal
inupdate_dict
может сбить с толку , потому что люди, читающие его, будут ожидать, что вы измените эту глобальную переменную (присвоите или переназначите ее)3. @juanpa.arrivillaga 1 — Это присвоение ключа объекту, который не был объявлен как dict . Откуда класс знает, что он должен использовать глобальную переменную?
4. Ваш класс никогда не использует глобальную переменную . В любом случае вам никогда не нужно объявлять переменные как глобальные, просто чтобы использовать их . Пожалуйста, прочтите, что я написал. Возможно
some_dict[key] = value
, вас смущает, это не простое назначение, напримерx = y
, скорее, это «назначение элемента», в основном синтаксический сахар дляsome_dict.__setitem__(key, value)
Вам нужно использоватьglobal some_var
оператор только тогда, когдаsome_var
он назначен в некоторой неглобальной области5. «Это присвоение ключа объекту, который не был объявлен как dict». Это не имеет никакого смысла. Я думаю, у вас фундаментальное недоразумение, python не имеет объявлений переменных, а переменные не имеют типов в Python, это динамически типизированный язык. Все
update_dict
, что происходит, происходит во время выполнения, и оно разрешается во время выполнения при вызове функции.
Ответ №1:
global varname
требуется только при назначении глобальной переменной, потому что в противном случае предполагается, что создается новая локальная переменная. Во всех остальных случаях Python уже знает, что она должна быть используемой глобальной, и двусмысленности нет.
В вашем примере кода вы устанавливаете пару ключ / значение для глобального dict, а не присваиваете глобальной переменной:
def update_dict(key):
my_dict[key] = ...
Следующий случай, когда вам нужно global
изменить глобальную b:
b = 0
def a():
global b
b = 2
print(b)
a()
print(b)
Вывод:
0
2
Комментарии:
1. функция класса присваивается глобальной переменной. Однако нет
global varname
. Кроме того, вы НЕ МОЖЕТЕ добавить новый ключ к anew local object
, который не был объявлен какdict
. Я удивлен, что скрипты работают, но я подозреваю, что результаты могут быть неверными.2. @aerijman что? Нигде вы не присваиваете глобальной переменной в методах вашего класса.
3.
mydict[key] = ...
не является присвоениемmydict
. Это синтаксический сахар дляmydict.__setitem__(key, ...)
, и его нетNameError
до тех пор, покаmydict
он определен в содержащей области передupdate_dict
вызовом . В частности,mydict
не нужно определять в то времяupdate_dict
, когда определяется само определение.4. @chepner 1- Спасибо! Мне трудно это понять. Является ли хорошей практикой объявлять функции, которые будут использовать переменные, которые будут объявлены в будущем, вместо того, чтобы передавать их функции в качестве аргументов?
5. Не совсем, нет. передавайте значения в качестве аргументов, когда это возможно.